import mongoose, { Schema, Model, Document, HookNextFunction } from 'mongoose';
import validator from 'validator';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
import { UserPayload } from '../typings/jwt';

export interface IUserDocument extends Document {
  username: string;
  password: string;
  email: string;
  avatat: string;
  generateToken: () => string;
  _doc: IUserDocument;
}

const UserSchema: Schema<IUserDocument> = new Schema(
  {
    username: {
      type: String,
      required: [true, '用户名不能为空'],
      minlength: [6, '最小长度不能少于6位'],
      maxlength: [12, '最大长度不能大于12位'],
    },
    password: String,
    avatat: String,
    email: {
      type: String,
      validate: { validator: validator.isEmail },
      trim: true,
    },
  },
  { timestamps: true }
);

UserSchema.methods.generateToken = function (): string {
  let payload: UserPayload = { id: this._id };
  console.log('======generateToken', process.env.JWT_SECRET_KEY);
  return jwt.sign(payload, process.env.JWT_SECRET_KEY!, {
    expiresIn: '1h',
  });
};

// 这个是干什么的
UserSchema.pre<IUserDocument>('save', async function (next: HookNextFunction) {
  // 是否修改密码
  if (!this.isModified('password')) {
    return next();
  }
  try {
    this.password = await bcrypt.hash(this.password, 10);
    next();
  } catch (error) {
    next(error);
  }
});

UserSchema.static('login', async function (
  this: any,
  username: string,
  password: string
): Promise<IUserDocument | null> {
  let user: IUserDocument | null = await this.model('User').findOne({ username });
  if (user) {
    const matched = await bcrypt.compare(password, user.password);
    if (matched) {
      return user;
    } else {
      return null;
    }
  }
  return user;
});

export interface IUserModel<T extends Document> extends Model<T> {
  login: (username: string, password: string) => IUserDocument | null;
}

export const User: IUserModel<IUserDocument> = mongoose.model<
  IUserDocument,
  IUserModel<IUserDocument>
>('User', UserSchema);
